home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / dos / pascal / eval_az.com / TESTLIB.PAS < prev   
Encoding:
Pascal/Delphi Source File  |  1989-07-11  |  22.0 KB  |  784 lines

  1. {-  Dataran Standard Library  Special Version for RTU}
  2. { designed to be used with TP Professional }
  3.  
  4. {$R-}    {Range checking off}
  5. {$B+}    {Boolean complete evaluation on}
  6. {$S-}    {Stack checking on}
  7. {$I-}    {I/O checking on}
  8.  
  9. Unit testlib;
  10.  
  11. Interface
  12. uses   Dos;
  13.  
  14. const
  15.   secs_per_minute = 60;
  16.   secs_per_hour  = 3600;
  17.   secs_per_day = 86400;  { number of sconds in a day }
  18.  
  19. { ASCII CHARACTERS }
  20. formfeed  =  ^L;    { formdeed character }
  21. alf       = ^J;    { ascii line feed}
  22. acr       =  ^M;    { ascii carrige return }
  23. aesc      = ^[;     { ascii escape }
  24. adel      = #127;   { ascii delete }
  25. absp      = #8;     { ascii back space }
  26. abell     = #7;     { beep }
  27. aus       = '_';      { ascii underscore }
  28. anak      = #21;      { NAK }
  29. aack      = #6;       { ack }
  30. axon      = #17;      { xon CTRL q }
  31. axoff     = #19;      { xoff ctrl S}
  32.  
  33. uparrow   = #24;   { graphic arrow keys}
  34. dnarrow   = #25;
  35. larrow    = #27;
  36. rarrow    = #26;
  37.  
  38. k_esc = $01;  k_bs = $0e;  k_enter = $1c;  k_home = $47;
  39. k_up = $48;  k_pgup = $49;  k_left = $4b;  k_right = $4d;
  40. k_end = $4f;  k_down = $50;  k_pgdn = $51;  k_ins = $52;
  41. k_del = $53;  k_f1 = $3b;  k_f2 = $3c;  k_f3 = $3d;  k_f4 = $3e;
  42.  
  43. caps   : boolean = false;   { true if upper case only wanted }
  44.  
  45.  
  46. { NUMERIC CONTROLS }
  47. intsmall  = -32767; { a small integer }
  48. intbig    = 32767;    { a big integer }
  49. longbig   =  2147483647;
  50. longsmall = -2147483647;
  51. realsmall = -9999999;
  52. realbig   = 99999999;
  53.  
  54. type
  55.  
  56.  regpack = registers;
  57.  
  58.  halfpack = record
  59.            al,ah,bl,bh,cl,ch,dl,dh : byte;
  60.          end;
  61.  maxstring = string[255];    { the biggest there is }
  62.  anystring = string[140];    { largest general purpose string }
  63.  filename  = string[30];     { tupical file name }
  64.  small_string = string[24];  { save stack space for small strin functions }
  65.  med_string   = string[134]; { long line type string }
  66.  charset    = set of char;
  67.  
  68.  timestr = string[8];    { holds formatted time as HH:MM:SS }
  69.  datestr = string[8];       { date asMM/DD/YY   }
  70.  
  71. (*  { old style parser }
  72.   parse_rec = record
  73.     parsed      : array[1..numparse] of string[parselen];  { holds parsed lines }
  74.     com_chr      : char;                                   { comment character }
  75.     sep_chr      : char;            { returns to caller sep char actually used }
  76.     primary_sep : char;            { use this for sep char if found in string }
  77.     option_sep  : char;        { alternate sep char to use if other not found }
  78.     tot_parsed  : integer;                        { number of elements parsed }
  79.     param_start : integer;     { returns position of first item after keyword }
  80.     in_buff     : ^maxstring;   { is set by procedure to point to input source }
  81.   end;
  82. *)
  83.  
  84.  
  85. { parser controls }
  86. const
  87. numparse = 32;   { number of parsed elements}
  88. {  parselen = 60;   { max size of each elemrnt }
  89.  
  90. type
  91.  
  92. { New style parser  using objects }
  93.   parse_type = object
  94.     in_buff     : ^maxstring;  { is set by procedure to point to input source }
  95.     com_chr      : char;        { comment character }
  96.     sep_chr     : char;        { returns to caller sep char actually used }
  97.     primary_sep : char;        { use this for sep char if found in string }
  98.     option_sep  : char;        { alternate sep char to use if other not found }
  99.     tot_len     : integer;     { length of raw line up to any comments}
  100.     tot_parsed  : integer;     { number of elements parsed }
  101.     param_start : integer;     { returns position of first item after keyword }
  102.     starts      : array[1..numparse] of byte;  { starting positions }
  103.     ends        : array[1..numparse] of byte;  { ending positions }
  104.     constructor init;
  105.     procedure parse(var instring: string);
  106.  
  107.     function parsed(i:integer) : med_string;  { pull out the i'th element }
  108.   end;
  109.  
  110.  
  111.  
  112. var            { variables used by all functions and procedures }
  113.  recpack          : regpack ;  { used to interface with msdos }
  114.  ah,al,ch,cl,dh   : byte;
  115.  
  116. procedure beep;
  117. procedure blip;
  118.  
  119.  
  120. function zfill(zstr : anystring) : anystring;
  121.  
  122. function time: timestr;    { returns formatted time }
  123. function secs_now  : longint;  { returns number of seconds sice midnite}
  124. function time_now : timestr; { returns string using secs_now  rather than dos}
  125. function num_secs( tt : timestr) : longint ; {returns number of secs since mid}
  126. function secs_to_time(l : longint) : timestr;
  127.  
  128.  
  129. function date: datestr;    { get system date and set variables }
  130.  
  131. procedure purge;
  132.  
  133. procedure backup(i : integer);   { backup i spaces on the tube }
  134.  
  135. procedure zap(i : integer);   { zap out i spaces and return  cursor }
  136.  
  137. procedure backzap(i : integer);
  138.  
  139. var funkey : boolean;   ext_char : integer;  { extnded key control }
  140.  
  141. function get_key : char;  { get a key and set function code if needed }
  142. function in_range(i,j,k : integer) : boolean;  { simple range check }
  143.  
  144.  
  145. procedure pause;               { wait for a CR or ESCAPE }
  146.  
  147. procedure pauseln;    { same as pause but with a new line after }
  148.  
  149. function exp10( xx : integer) : real;  { return 10 to the xx}
  150.  
  151. function rnd(xx : real; yy : integer) : real;  { round a real to yy dec places }
  152.  
  153. procedure stick(X : anystring; var Y : anystring; n : integer);
  154.  
  155. function clean_string(s : string) : string;
  156.  
  157. function power(y,x : real) : real;  { calculate y to the X power }
  158.  
  159. { rules are if X = 0, answer = 1
  160.             if y = 0, answer = 0
  161.             if y < 0, answer = - of positive answer.
  162.             if x < 0, answer is 1/ positive answer. }
  163.  
  164. function color_display : boolean;  { true if this is color }
  165.  
  166. procedure far_call(p : pointer);  { calls a pointer address like a program}
  167.  
  168. function attr(fore, back : integer) : integer;
  169.  
  170.  
  171. { the following 2 are inline macros, not real procedures }
  172.  
  173. procedure save_and_stop; inline($9c/$Fa);  { clear interupts (stop them }
  174.  
  175. procedure restore_flags; inline($9D);       { popf }
  176.  
  177. function check_8087 : small_string;
  178. function pull_char(s :string ; i : integer) : char;
  179. function pull_upcase(s :string ; i : integer) : char;  { upper cae versin}
  180.  
  181.  
  182.  
  183.  
  184. {===========================================================================}
  185.  
  186. implementation
  187.  
  188.  
  189. Uses
  190.   tpCrt,
  191.   tpstring, tpedit;
  192.  
  193. function check_8087 : small_string;
  194. var
  195.  m : integer;
  196.  s : string[5];
  197. begin
  198.   s := '?????';
  199.   m := test8087;
  200.   case m of
  201.     0 : s := 'NONE ';
  202.     1 : s := '8087 ';
  203.     2 : s := '80287';
  204.     3 : s := '80387';
  205.   end;  { case }
  206.   check_8087 := s;
  207. end;
  208.  
  209.  
  210. procedure beep;
  211. begin
  212. sound(1200); delay(125); nosound; delay(125);
  213. sound(1200); delay(125); nosound;
  214.  
  215. end;
  216.  
  217. procedure blip;
  218. begin
  219.   sound(1800);  delay(20); sound(900); delay(20); nosound;
  220. end;
  221.  
  222.  
  223. function date;
  224. var
  225.   year,month,day : string[2];
  226.   i_y,i_m,i_d,i_dow : word;
  227. begin                       { uses function 2A hex from MS-DOS }
  228.   getdate(i_y,i_m,i_D,i_dow);
  229.   i_y := i_y-1900;     { lets use a 2 digit year }
  230.   str(i_y:2,year);     { convert bins to strings }
  231.   str(i_d:2,day);
  232.   str(i_m:2, month);
  233.   month := zfill(month); day := zfill(day);
  234.  
  235.   date := month + '/'+day+'/'+year
  236. end;    { of date function }
  237.  
  238. procedure purge;
  239. var c : char;
  240. begin
  241. while keypressed do c := readkey;
  242. end;
  243.  
  244. procedure backup;
  245. var j : integer ;
  246. begin
  247. for  j := 1 to i do write(absp);
  248. end;
  249.  
  250. procedure zap;
  251. var j : integer;
  252. begin
  253. for j := 1 to i do write(' ');    { put spaces over existing chars first }
  254. backup(i);                        { restore cursor }
  255. end;
  256.  
  257. procedure backzap;
  258. var j : integer;
  259. begin
  260. backup(i);
  261. zap(i);
  262. end;
  263.  
  264.  
  265. function get_key;
  266. var ch : char;
  267. begin
  268.   funkey := false;  ext_char := 0;  { assume no special character }
  269.   ch := readkey;          { read and wait }
  270.   if (ch = #27) and keypressed then begin       { one mode character }
  271.     ch := readkey;  funkey := true;
  272.     ext_char := ord(ch);  { save extended char }
  273.     ch := #27;   { play like an escape came in }
  274.   end;
  275.   get_key := ch;
  276. end;
  277.  
  278.  
  279. procedure pause;               { wait for a CR or ESCAPE }
  280.  
  281. var
  282. x : char;
  283. begin
  284. purge;
  285. write('...[RET]...');
  286. repeat
  287.   x := readkey;
  288. until (x = acr) or (x = aesc);         { wait for an actual carrige return }
  289. backzap(11);
  290. end;                   { simple huh ??? }
  291.  
  292. procedure pauseln;    { same as pause but with a new line after }
  293. begin
  294. pause;
  295. writeln;
  296. end;
  297.  
  298.  
  299. function exp10;
  300. var
  301. i,j : integer;
  302. treal  : real;
  303.  
  304. begin
  305.  
  306.   if xx = 0 then treal := 1;  { 10 to 0 = 1 }
  307.  
  308.   treal := 1;
  309.  
  310.   if xx > 0 then begin
  311.     for i := 1 to xx do treal := treal * 10;
  312.   end;
  313.  
  314.   if xx < 0 then begin
  315.    j := - xx;
  316.    for i := 1 to j do treal := treal / 10;
  317.  end;
  318.  
  319.  exp10 := treal;
  320. end;
  321.  
  322. function rnd;
  323. var
  324. i  : integer;
  325. treal1,treal  : real;
  326.  
  327. factor : real;
  328. begin
  329.  
  330.   if yy = 0 then begin
  331.     treal := xx + 0.5;
  332.     treal := int(treal);        { no decimal places }
  333.   end;
  334.  
  335.   if yy > 0 then begin   { places to right of decimal point }
  336.     treal1 := exp10(yy);
  337.     treal := xx * treal1+0.5;   { move it to the left }
  338.     treal := int(treal);
  339.     treal := treal / treal1;  { move back to right }
  340.   end;
  341.  
  342.   if yy < 0   then begin
  343.     treal1 := exp10(yy);
  344.     treal := xx * treal1 + 0.5;   { move to right }
  345.     treal := int(treal);     { chop it off }
  346.     treal := treal / treal1;   { move back to left }
  347.   end;
  348.  
  349.   rnd := treal;
  350. end;
  351.  
  352.  
  353.  
  354. function zfill;
  355.   var indx, len  : integer;
  356.   begin
  357.    len := length(zstr);  { how much we have to fool with }
  358.    if len <> 0 then
  359.    begin
  360.     indx := 1;
  361.     repeat   { scan thru string till <> blank or end }
  362.       if zstr[indx] = ' ' then zstr[indx] := '0';
  363.       indx := indx+1;
  364.     until (indx > len) or ( zstr[indx] <> ' ' );
  365.    zfill := zstr;
  366.    end;  { of <> length block }
  367.   end;   { of zfill procedure }
  368.  
  369. procedure stick(X : anystring; var Y : anystring; n : integer);
  370. var i  : integer;
  371.  
  372. begin
  373.   i := length(x) + n;   { total length of final string }
  374.   if length(y) < i  then  { need to extend the string }
  375.     y := pad(y, i - length(y));
  376.   for i := 1 to length(x) do begin
  377.     y[i-1+n] := x[i];  { move in a single character }
  378.   end;
  379. end;  { of stick }
  380.  
  381.  
  382. { This will trim, case convert, and change any spaces to
  383.   underscors.  Useful for filenames and tags
  384. }
  385. function clean_string(s : string) : string;
  386. var
  387. ss : string;
  388. i : integer;
  389. begin
  390.   ss := trim(s);
  391.   ss := stupcase(ss);
  392.   while pos(' ',ss) <> 0 do begin
  393.     i :=pos(' ',ss);
  394.     ss[i] := '_';
  395.   end;  { changing spaces }
  396.   clean_string := ss;
  397. end;
  398.  
  399.  
  400. function power;
  401.  
  402. { rules are if X = 0, answer = 1
  403.             if y = 0, answer = 0
  404.             if y < 0, answer = - of positive answer.
  405.             if x < 0, answer is 1/ positive answer. }
  406. var
  407. r1,r2,r3 : real;
  408. done : boolean;
  409.  
  410. begin
  411.   r1 := abs(x);  r2 := abs(y);
  412.   done := false;
  413.  
  414.   if x = 0 then begin
  415.     r3   := 1;            { always 1 for 0 exponent }
  416.     done := true;
  417.   end;
  418.  
  419.   if y = 0 then begin
  420.     r3 := 0;            { always 0 for 0 number }
  421.     done := true;
  422.   end;
  423.  
  424.   if not done then begin   { still need to calculate }
  425.     r3 := exp( ln(r2) * r1);  { basic calculatin }
  426.  
  427.     if y < 0 then r3 := -1 * r3;    { negate if number < 0 }
  428.     if x < 0 then r3 := 1/r3;       { flip over if exponent negative }
  429.   end;
  430.  
  431.   power := r3;
  432.  
  433. end;  {  power function }
  434.  
  435.  
  436.  
  437. { Convert a number of seconds into a time string }
  438. function secs_to_time(l : longint) : timestr;
  439. var h,m,s : integer;
  440.   s_hour,s_min,s_sec : string[2];
  441.  
  442. begin
  443.   h := l div 3600;     { how many hours worth of seconds}
  444.   m := l - (h*3600);     { now many secs left after hours taken out }
  445.   m := m div 60;       { equivalent minutes to that many seconds}
  446.   s := l - (h*3600) - (m*60);
  447.  
  448.   str(h:2, s_hour);     { convert returned values to strings }
  449.   str(m:2, s_min);
  450.   str(s:2, s_sec);
  451.   s_hour := zfill(s_hour); s_min := zfill(s_min);
  452.   s_sec := zfill(s_sec);  { force leading 0 }
  453.   secs_to_time := s_hour+':'+s_min+':'+s_sec;
  454. end;
  455.  
  456.  
  457. { Return current time as number of secs since midnite }
  458. function secs_now  : longint;  { returns number of seconds sice midnite
  459.                                 { using counter in bios memory area }
  460. var
  461.  r : real;
  462. begin
  463.   r := meml[0:$46c]  / 18.2065;
  464.   secs_now := trunc(r);
  465. end;
  466.  
  467. { return current time as a string }
  468. function time_now : timestr; { returns string using secs_now  rather than dos}
  469. begin
  470.   time_now := secs_to_time(secs_now);
  471. end;
  472.  
  473.  
  474. function time : timestr;
  475. begin
  476.   time := time_now;
  477. end;
  478.  
  479.  
  480. function num_secs( tt : timestr) : longint ; {returns number of secs from time string}
  481.  
  482. var  x,H,M,S : longint;
  483.   t : timestr;
  484.   ok : boolean;
  485. begin
  486.   t := tt;     { local copy }
  487.   if length(t) < 8 then t := padch(t,'0', 8-length(t) );
  488.   ok := str2long(copy(t,1,2),H); { hours first }
  489.   if ok then ok :=  str2long(copy(t,4,2),m);  { minutes }
  490.   if ok then ok := str2long(copy(t,7,2),s);  { secs }
  491.   if ok then num_secs := (h*3600) + (m * 60) + s
  492.     else num_secs := -1;  { negative nuimber is error }
  493.  
  494. end;
  495.  
  496.  
  497. constructor parse_type.init;
  498. begin
  499.    { dummy to build object }
  500.   primary_sep := ',';  option_sep := ' '; com_chr := ';';
  501. end;
  502.  
  503.  
  504. { Parse as an object.  Set up the options, and then call parse.  Then
  505.   obtain any eleent by using the methid parsed[x].  This makes it very
  506.   similar to the old way of parsing out actual strings except that
  507.   VAR references will not be allowed.  However, this takes up LOTS less memory
  508.  
  509.   What this does is to examine the input line and set up indexes into
  510.   each element on the line.
  511.  
  512.   If spaces are the delimter, each element is "trimmed" by moving the
  513.   start position to the first non space field.  This means that multiple
  514.   spaces on the line count as a single separator.
  515. }
  516.  
  517. procedure parse_type.parse(var instring: string);
  518.  
  519.  var
  520.   comma, start, finish : word;
  521.   xnay, pntr : integer ;
  522.   double : string[2];    { check for occurance of doubles }
  523.   i, field_num, index : integer;       { as we march across the line }
  524.   all_done : boolean;
  525.  
  526.  
  527. { This will advance the index to the first non space char on the line}
  528. procedure eat_spaces;
  529. var ready : boolean;
  530. begin
  531.   ready :=  false;
  532.   while ((index <= tot_len) and   (not ready)) do
  533.     if in_buff^[index] = ' ' then inc(index)
  534.     else ready :=  true
  535. end;
  536.  
  537. begin
  538.     for index := 1 to numparse do begin   { clear out the old parsed table }
  539.       starts[index] := 0;  ends[index] := 0;
  540.     end;
  541.  
  542.     tot_parsed  := 0;            { assume none }
  543.     tot_len     := 0;            { length up to comment character }
  544.     param_start := 0;            { first parameter after possible keyword}
  545.  
  546.     in_buff := @instring;        { where we will get out input from }
  547.  
  548.     if length(in_buff^) = 0 then exit;  { null line, so real simple }
  549.  
  550.     index := 1;   { current position on the line}
  551.     start := 1;   { start of search in the buffer }
  552.  
  553.     i := pos(com_chr, in_buff^);  { see if a comment is present anywere}
  554.  
  555.     if i <> 0 then tot_len := i-1      { chop as needed }
  556.     else tot_len := length(in_buff^);
  557.  
  558. {
  559.   Here we decide on the field separator.  If the primary sep is found
  560.   the it wins.  If it is not found then the secondary set wins
  561.   Use optional separator if primary separator is not in string.
  562. }
  563.     comma := search(in_buff^[1], tot_len, primary_sep, 1);
  564.  
  565.     if comma <> $FFFF then sep_chr := primary_sep
  566.     else sep_chr := option_sep;
  567.  
  568. { Now that the seps are determined, scan the line looking for them }
  569.     tot_parsed := 1;     { now identifying the first element }
  570.     eat_spaces;         { move up to the first non blank char }
  571.     starts[1] := index;  { where the first non_space char occurs }
  572.     all_done := false;
  573.  
  574.     if index < tot_len then
  575.     repeat  { keep looking for more entres }
  576.       if index <= tot_len then       { not at the end as yet }
  577.         finish := tot_len - index +1        { how much usable string is left }
  578.       else finish := 0;   { chars left to examine }
  579.  
  580. { search will return the number of chars SKIPPED, starting at INDEX }
  581.       if finish <> 0 then
  582.       comma := search(in_buff^[index], finish, sep_chr, 1)
  583.       else comma := $ffff;  { end of the line }
  584.  
  585.       if comma = $FFFF then begin  { no more seps found }
  586.         ends[tot_parsed] := tot_len;  { last one ends at the end of the line}
  587.         all_done := true;
  588.       end
  589.  
  590.       else  begin                 { we found a separator }
  591.         index := index + comma ;  { where the next separator was on the line }
  592.         ends[tot_parsed] := index - 1;  { finish previous field }
  593.         inc(index);       { skip over the just found separator }
  594.         eat_spaces;  { advance index to next non space }
  595. { this may bring us out to the end of the line with no mode entries }
  596.  
  597.         if index <= tot_len then begin { still more to come }
  598.           inc(tot_parsed);  { move on to the next field }
  599.           if tot_parsed = 2 then param_start := index;  { if starting # 2 }
  600.  
  601.           starts[tot_parsed] := index;  { start of the next field }
  602.           ends[tot_parsed] := index;    { asssume very short field }
  603.         end;
  604.       end;  { finding the start of a field }
  605.  
  606.     { return to caller position of first item after keyword }
  607.  
  608.       if (index > tot_len) or (tot_parsed > numparse) then all_done := true;
  609.     until all_done;                     { finish went to 0 meaning no more }
  610.  
  611.  
  612. end;    { end of parse proc }
  613.  
  614.  
  615. function parse_type.parsed(i : integer) : med_string;
  616. begin
  617.   if i > tot_parsed then begin
  618.     parsed := '';  exit;
  619.   end;
  620.  
  621.   parsed := copy(in_buff^, starts[i], ends[i]-starts[i]+1);
  622.  
  623. end;
  624.  
  625.  
  626.  
  627.  
  628. { Old style string based general purpose text line parser
  629.  
  630. This proc takes a string as an argument and breaks it up into smaller
  631. pieces.  THe plan is to pull out pieces separated by sep_chr and remove
  632. any leading or trailing blanks.
  633.  
  634. Any double occurances of a sep_chr are reduced to a single occurance
  635. to allow multiple blanks (or whatever) tp separate entries.
  636.  
  637. a previous CONST section must define:
  638.    numparse    - The number of elements in the parsed array
  639.    parselen    - length of each string in the parsed array
  640.  
  641. This version will set the address of the string into the parse record
  642. during processing.  It is not assumed to be correct in the record
  643. prior to entry.
  644.  
  645. }
  646. (*
  647.  
  648. procedure parse( var instring : string; var par_rec : parse_rec);  { general purpose parser}
  649.  
  650.  var
  651.   xnay, comma, pntr, indx, len, start, finish   : integer ;   { locals }
  652.   buf  : anystring;
  653.   double : string[2];    { check for occurance of doubles }
  654.  
  655. begin
  656.  
  657.     for indx := 1 to numparse    { clear out the old parsed table }
  658.       do  parsed[indx] := '';
  659.  
  660.     tot_parsed := 0;             { assume none }
  661.     param_start := 0;
  662.  
  663.     in_buff := @instring;
  664.     buf := trim(in_buff^);   { get a local copy  of original}
  665.     if pos(com_chr, buf) <> 0 then
  666.       buf := copy(buf,1,pos(com_chr, buf)-1);  { strip comment }
  667.  
  668. { use optional separator if primary separator is not in string }
  669.     if pos(primary_sep, buf) <> 0 then
  670.       sep_chr := primary_sep
  671.     else
  672.       sep_chr := option_sep;
  673.  
  674. { check for all double separaters and reduce them to a single if the
  675.   separator is a blank }
  676.  
  677.     if sep_chr = ' ' then begin
  678.       double := sep_chr + sep_chr;
  679.       repeat
  680.         comma := pos( double, buf);   { any doubles left }
  681.         if comma <> 0 then delete(buf, comma, 1);  { get rid of sep char}
  682.       until comma = 0;
  683.     end
  684.  
  685. { check for all double separators and insert a space between them if the
  686.   separator is not a blank }
  687.  
  688.     else begin
  689.       double := sep_chr + sep_chr;
  690.       repeat
  691.         comma := pos( double, buf);                       { any doubles left }
  692.         if comma <> 0 then insert(' ', buf, comma+1);   { get rid of sep char}
  693.       until comma = 0;
  694.     end;
  695.  
  696.     len := length(buf);                            { total chars to scan thru }
  697.     if len <> 0 then  begin                        { dont process blank lines }
  698.       indx:=1;                  { keeps track of parsed result array position }
  699.       start := 1;                                { start at beginning of line }
  700.  
  701.       repeat                                        { up to 10 entries or len }
  702.         comma := pos(sep_chr, copy(buf,start,len));  { comma loc relative to start }
  703.         finish := start+comma-1;                      { comma relative to buf }
  704.  
  705.         if comma <> 0 then
  706.           parsed[indx] := copy(buf,start, finish-start)   { raw grab from buf}
  707.         else
  708.           parsed[indx] := copy(buf,start,len);           { grab rest of line }
  709.  
  710.         parsed[indx] := trim(parsed[indx]);   { get rid of leading and trailing blanks }
  711.  
  712.       { return to caller position of first item after keyword }
  713.         if indx = 2 then
  714.           param_start := start;
  715.  
  716.         start := finish+1;                              { skip over the comma }
  717.         tot_parsed := indx;                    { global count of total parsed }
  718.         indx := indx + 1;                        { next parsed array location }
  719.       until (comma = 0 ) or (start > len) or (indx > numparse);
  720.                                            { finish went to 0 meaning no more }
  721.     end;                                         { of non blank line to parse }
  722.  
  723.  
  724. *)
  725.  
  726. function color_display : boolean; { return tue if in color mode }
  727. var
  728.   Reg        : Registers;
  729.   colorcard  :boolean;
  730.  
  731. begin
  732.   Reg.AH := 15;
  733.   Intr($10, Reg);
  734.   ColorCard := Reg.AL <> 7;
  735.   if ColorCard then
  736.     color_display := true
  737.   else
  738.     color_display := false;
  739. end;
  740.  
  741.  
  742. procedure far_call(p : pointer);  { calls non nill address }
  743. var
  744.   a_loc : pointer;
  745. begin
  746.   a_loc := p;
  747.   if a_loc <> nil then
  748.   inline ($36/$ff/$9E/>a_loc);  { ss: call far [a_loc]bp }
  749. end;
  750.  
  751.  
  752. function attr;
  753. var
  754.   temp : byte;
  755. begin
  756.   temp := (back*16)+fore;
  757.   if fore > 15 then temp := temp + 112;
  758.   attr := temp;
  759. end;
  760.  
  761. function in_range(i,j,k : integer) : boolean;  { simple range check }
  762.  
  763. begin
  764.   in_range := (i >= j) and (i <= k);
  765. end;
  766.  
  767. function pull_char(s :string ; i : integer) : char;
  768. begin
  769.   if i <= length(s) then pull_char := s[i] else pull_char := #0;
  770. end;
  771.  
  772. function pull_upcase(s :string ; i : integer) : char;
  773. var c : char;
  774. begin
  775.   if i <= length(s) then begin
  776.     c := s[i] ; pull_upcase := upcase(C)
  777.   end
  778.   else pull_upcase := #0;
  779. end;
  780.  
  781.  
  782. begin
  783. end.
  784.